'use strict';
var SchedulerModel = require('../models/Scheduler.server.model.js'),
	Schedule = require("node-schedule"),
	BaseFun = require('../../../Base/server/controllers/Function'),
	entityCollection = require('../../../Base/server/controllers/EntityCollection'),
	CommonEnum = require('../controllers/Enum.js');
var path = require('path');

var _scheduleRequests = {};
var _schedulers = [];
var schedulerEntity = entityCollection.getEntity('Scheduler');

//有可能由于服务器停止产生执行中状态的调度请求，先将执行中的更新为等待执行
entityCollection.getEntity('ScheduleRequest').updateByValue({Status: 2}, {Status: 1}, function(err){
	entityCollection.getEntity('ScheduleRequest').find({Status: 1}, {Code: 1}, [{path: 'Scheduler'}, {path: 'ScheduleProgram'}], function(err, records){
		if(err){
			throw err;
		}
		else{
			records.forEach(function(srRecord, i){
				createSchedule(srRecord);
			});
		}
	});
});

//计算执行调度时间
var computeRequestTime = function(srRecord){
	var nowDate = new Date();
	var executeTime = srRecord.ScheduleProgram.FirstTime; 	//执行时间
	if(srRecord.LastRequestTime){
		executeTime = srRecord.LastRequestTime;
	}

	//计算下一个执行时间
	while(executeTime.getTime() < nowDate.getTime()){
		executeTime.setFullYear(executeTime.getFullYear() + srRecord.ScheduleProgram.Years);
		executeTime.setMonth(executeTime.getMonth() + srRecord.ScheduleProgram.Months);

		executeTime.setDate(executeTime.getDate() + srRecord.ScheduleProgram.Days);
		executeTime.setHours(executeTime.getHours() + srRecord.ScheduleProgram.Hours);
		executeTime.setMinutes(executeTime.getMinutes() + srRecord.ScheduleProgram.Minutes);
		executeTime.setSeconds(executeTime.getSeconds() + srRecord.ScheduleProgram.Seconds);
	}
	
	if(srRecord.ScheduleProgram.EndMode == CommonEnum.EndMode.Repeat.Value){
		if((srRecord.ExecuteTimes ? srRecord.ExecuteTimes : 0) >= srRecord.ScheduleProgram.RepeatTimes){
			return null;
		}
		else{
			return executeTime;
		}
	}
	else if(srRecord.ScheduleProgram.EndMode == CommonEnum.EndMode.EndTime.Value){
		if((new Date()).getTime() >= srRecord.ScheduleProgram.EndTime.getTime()){
			return null;
		}
		else{
			return executeTime;
		}
	}
	else{
		return executeTime;
	}
};

//创建调度
//dateTime: 调度执行时间，srRecord: 调度请求记录
var createSchedule = function(srRecord){
	var requestTime = computeRequestTime(srRecord);
	if(requestTime){
		var job = Schedule.scheduleJob(requestTime, function(){
			var requestRecord = null;

			//检查记录是否还存在
			getScheduleRequestById(srRecord._id).then(function(record){
				if(record && record.Status == CommonEnum.ScheduleStatus.Wait.Value){
					requestRecord = record;
					//1，更新状态为执行中和最后一次请求时间
					updateScheduleRequest(
						requestRecord._id,
						{ Status: CommonEnum.ScheduleStatus.Execution.Value, LastRequestTime: requestTime}
					).then(function(data){
						requestRecord.LastRequestTime = requestTime;
						//2，执行请求
						executeRequest(requestRecord).then(function(isSuccess){
							var requestData = {
								ExecuteTimes: (requestRecord.ExecuteTimes ? requestRecord.ExecuteTimes : 0) + 1	//请求次数
							};

							if(requestRecord.ScheduleProgram.EndMode == CommonEnum.EndMode.Repeat.Value){
								if(requestData.ExecuteTimes >= requestRecord.ScheduleProgram.RepeatTimes){
									requestData.Status = CommonEnum.ScheduleStatus.Complete.Value;
								}
								else{
									requestData.Status = CommonEnum.ScheduleStatus.Wait.Value;
								}
							}
							else if(requestRecord.ScheduleProgram.EndMode == CommonEnum.EndMode.EndTime.Value){
								if((new Date()).getTime() >= requestRecord.ScheduleProgram.EndTime.getTime()){
									requestData.Status = CommonEnum.ScheduleStatus.Complete.Value;
								}
								else{
									requestData.Status = CommonEnum.ScheduleStatus.Wait.Value;
								}
							}
							else{
								requestData.Status = CommonEnum.ScheduleStatus.Wait.Value;
							}

							//3.1，更新调度请求状态、执行次数
							updateScheduleRequest(requestRecord._id, requestData).catch(function(err){
								BaseFun.errorLog(err.title, err.message);
							});

							//3.2，插入监控记录
							var recordUpdateData = {
								ScheduleRequest: requestRecord._id,
								IsSuccess: true,
								StartTime: requestTime,
								EndTime: new Date()
							};
							insertScheduleMonitor(recordUpdateData).then(function(data){}).catch(function(err){
								BaseFun.errorLog(err.title, err.message);
							});

							//4, 取消调度
							cancelSchedule(requestRecord._id);
							//5, 重新创建新的调度
							if(requestData.Status == CommonEnum.ScheduleStatus.Wait.Value){
								requestRecord.ExecuteTimes = requestData.ExecuteTimes;
								createSchedule(requestRecord);
							}							
						}).catch(function(err){
							//3, 取消调度
							cancelSchedule(requestRecord._id);
							if(!requestRecord.ExecuteTimes){
								requestRecord.ExecuteTimes = 0;
							}

							//4.1 更改调度请求状态为 待执行
							updateScheduleRequest(requestRecord._id, { 
								Status: CommonEnum.ScheduleStatus.Wait.Value,
								ExecuteTimes:  requestRecord.ExecuteTimes + 1
							}).catch(function(err){
								BaseFun.errorLog(err.title, err.message);
							});

							//4.2 插入执行失败监控记录
							var recordUpdateData = {
								ScheduleRequest: requestRecord._id,
								IsSuccess: false,
								StartTime: requestTime,
								EndTime: new Date(),
								Exception: err.message
							};
							insertScheduleMonitor(recordUpdateData).catch(function(err){
								BaseFun.errorLog(err.title, err.message);
							});
						});
					}).catch(function(err){
						BaseFun.errorLog(err.title, err.message);
						//插入更新失败监控记录
						var recordUpdateData = {
							ScheduleRequest: requestRecord._id,
							IsSuccess: false,
							StartTime: requestTime,
							EndTime: new Date(),
							Exception: err.title + "：" + err.message
						};
						insertScheduleMonitor(recordUpdateData).catch(function(err){
							BaseFun.errorLog(err.title, err.message);
						});
					});
				}
				else{
					BaseFun.errorLog('调度请求查找失败', '没有找到对应id的调度请求记录或者调度请求已完成');
					//插入查找调度请求记录失败的监控记录
					var recordUpdateData = {
						ScheduleRequest: requestRecord._id,
						IsSuccess: false,
						StartTime: requestTime,
						EndTime: new Date(),
						Exception: '没有找到对应id(' + requestRecord._id + ')的调度请求记录'
					};
					insertScheduleMonitor(recordUpdateData).then(function(record){  }).catch(function(err){
						BaseFun.errorLog(err.title, err.message);
					});
				}
			}).catch(function(err){
				BaseFun.errorLog(err.title, err.message);
				//插入查找调度请求记录错误的监控记录
				var recordUpdateData = {
					ScheduleRequest: requestRecord._id,
					IsSuccess: false,
					StartTime: requestTime,
					EndTime: new Date(),
					Exception: err.title + "：" + err.message
				};
				insertScheduleMonitor(recordUpdateData).then(function(record){  }).catch(function(err){
					BaseFun.errorLog(err.title, err.message);
				});
			});
		});

		_scheduleRequests[srRecord._id] = {
			Job: job,
			SchedulerId: srRecord.Scheduler
		};
	}
	else{
		//更改调度请求状态为 完成
		updateScheduleRequest(srRecord._id, { Status: CommonEnum.ScheduleStatus.Complete.Value }).catch(function(err){
			BaseFun.errorLog(err.title, err.message);
		});
	}
};

//执行调度
var executeRequest = function(srRecord){
	return new Promise(function(resolve, reject) {
		var requireModule = require(path.resolve(srRecord.Scheduler.ModuleUrl));
		var executeFun = requireModule[srRecord.Scheduler.FunctionName];
		if(executeFun){
			try{
				var result = executeFun();
				if(result && result.constructor === Promise){
					result.then(function(data){
						BaseFun.executeLog('调度执行成功', '调度请求【' + srRecord.Name + '】执行成功');
						resolve(data);
					}).catch(function(err){
                        var newErr = new Error();
			            newErr.leval = 1;
			            newErr.title = '【' + srRecord.Name + '】' + '调度程序内部抛异常';
			            newErr.message = err.message;
			            BaseFun.errorLog(newErr.title, err.message);
			            reject(newErr);
                    });
				}
				else{
					resolve(true);
				}
			}
			catch(err){
				var newErr = new Error();
	            newErr.leval = 1;
	            newErr.title = '【' + srRecord.Name + '】' + '执行错误';
	            newErr.message = '调度请求方法执行失败，程序已自动取消该调度请求，请检查调度请求方法代码';
	            reject(newErr);
			}
		}
		else{
			var newErr = new Error();
            newErr.leval = 1;
            newErr.title = '【' + srRecord.Name + '】' + '执行错误';
            newErr.message = '调度程序方法不存在，程序已自动取消该调度请求，请检查调度请求方法代码';
            reject(newErr);
		}
	});
};

//取消调度
var cancelSchedule = function(srRecordId){
	if(_scheduleRequests[srRecordId]) {
		if(_scheduleRequests[srRecordId].Job) {
            _scheduleRequests[srRecordId].Job.cancel();
        }
        delete _scheduleRequests[srRecordId];
    }
};

//更新调度请求
var updateScheduleRequest = function(id, data){
    return new Promise(function(resolve, reject) {
    	var scheduleRequestEntity = entityCollection.getEntity('ScheduleRequest');
		scheduleRequestEntity.updateByValue(
			{_id: id}, data,
			function(err){
				if(err){
					var newErr = new Error();
	                newErr.leval = 1;
	                newErr.title = '【' + scheduleRequestEntity.Name + '】' + '更新错误';
	                newErr.message = err.message;
	                reject(newErr);
				}
				else{
					resolve(id);
				}
			}
		);
	});
};

//获取调度请求记录
var getScheduleRequestById = function(id){
    var promise = new Promise(function(resolve, reject) {
    	var scheduleRequestEntity = entityCollection.getEntity('ScheduleRequest');
        scheduleRequestEntity.findById(id, [{path: 'Scheduler'}, {path: 'ScheduleProgram'}], function(err, record){
			if(err){
				var newErr = new Error();
                newErr.leval = 1;
                newErr.title = '【' + scheduleRequestEntity.Name + '】' + '查找错误';
                newErr.message = err.message;
                reject(newErr);
			}
			else{
				resolve(record);
			}
		});
    });
    return promise;
};

//插入监控记录
var insertScheduleMonitor = function(recordData){
	return new Promise(function(resolve, reject) {
		var scheduleMonitorEntity = entityCollection.getEntity('ScheduleMonitor');
		scheduleMonitorEntity.insert(recordData, function(err, data){
			if(err){
                reject(err);
			}
			else{
				resolve(data);
			}
		});
	});
};

// var requireModule = require(path.resolve('modules/Base/server/controllers/Function'));
// console.log(requireModule['getGuid']());

//添加调度方案
module.exports.addScheduler = function(code, name, remark, moduleUrl, functionName){
	var scheduleRequestEntity = entityCollection.getEntity('Scheduler');
	schedulerEntity.findOne({Code: code}, null, function(err, data){
		if(err){
			throw err;
		}
		else{
			var record = {
				Code: code,
				Name: name,
				ModuleUrl: moduleUrl,
				FunctionName: functionName,
				Remark: remark
			};
			if(data == null){
				schedulerEntity.insert(record, function(err, data){
					if(err){
						throw err;
					}
					else{
						// _schedulers.push(data);
					}
				});
			}
			else{
				schedulerEntity.updateByValue({_id: data._id}, record, function(err, data){
					if(err){
						throw err;
					}
					else{
						// _schedulers.push(data);
					}
				});
			}
		}
	});
};

//提交请求
module.exports.submitRequests = function(req, responseFun) {
	var parameter = req.body;
	var srRecordIds = parameter.ScheduleRequestIds;
	var scheduleRequestEntity = entityCollection.getEntity('ScheduleRequest');
    scheduleRequestEntity.find({_id: {$in: srRecordIds}, Status: CommonEnum.ScheduleStatus.No.Value}, null, [{path: 'Scheduler'}, {path: 'ScheduleProgram'}], function(err, records){
		if(err){
			var newErr = new Error();
            newErr.leval = 1;
            newErr.title = '【' + scheduleRequestEntity.Name + '】' + '查找错误';
            newErr.message = err.message;
            responseFun(newErr);
		}
		else{
			var recordIds = [];
			records.forEach(function(srRecord){
				recordIds.push(srRecord._id);
				createSchedule(srRecord);
			});

			var updateValue = {
				Status: CommonEnum.ScheduleStatus.Wait.Value,
				Submitter: req.user.Code
			};

 			scheduleRequestEntity.updateByValue({_id: {$in: recordIds}}, updateValue, function(err, data){
				if(err){
					var newErr = new Error();
		            newErr.leval = 1;
		            newErr.title = '【' + scheduleRequestEntity.Name + '】' + '更新出错';
		            newErr.message = err.message;
		            responseFun(newErr);
				}
				else{
					scheduleRequestEntity.find({_id: {$in: recordIds}}, null, [{path: 'Scheduler'}, {path: 'ScheduleProgram'}], function(err, records){
						responseFun(err, records);
					});
				}
			});
		}
	});
};

//取消调度
module.exports.cancelRequests = function(req, responseFun) {
	var parameter = req.body;
	var srRecordIds = parameter.CancelRequestIds;
	var scheduleRequestEntity = entityCollection.getEntity('ScheduleRequest');
    scheduleRequestEntity.find({_id: {$in: srRecordIds}, Status: CommonEnum.ScheduleStatus.Wait.Value}, null, [{path: 'Scheduler'}, {path: 'ScheduleProgram'}], function(err, records){
		if(err){
			var newErr = new Error();
            newErr.leval = 1;
            newErr.title = '取消调度：【' + scheduleRequestEntity.Name + '】' + '查找错误';
            newErr.message = err.message;
            responseFun(newErr);
		}
		else{
			var recordIds = [];
			records.forEach(function(srRecord){
				recordIds.push(srRecord._id);
				cancelSchedule(srRecord._id);
			});

			var updateValue = {
				Status: CommonEnum.ScheduleStatus.No.Value,
				CancelPerson: req.user.Code,
				CancelTime: new Date()
			};

			//更新状态
 			scheduleRequestEntity.updateByValue({_id: {$in: recordIds}}, updateValue, function(err, data){
				if(err){
					var newErr = new Error();
		            newErr.leval = 1;
		            newErr.title = '取消调度：【' + scheduleRequestEntity.Name + '】' + '更新出错';
		            newErr.message = err.message;
		            responseFun(newErr);
				}
				else{
					scheduleRequestEntity.find({_id: {$in: recordIds}}, null, [{path: 'Scheduler'}, {path: 'ScheduleProgram'}], function(err, records){
						responseFun(err, records);
					});
				}
			});
		}
	});
};

//执行调度程序
module.exports.executeSchedulers = function(req, responseFun){
	var parameter = req.body;
	var schedulerIds = parameter.SchedulerIds;

	var scheduleRequestEntity = entityCollection.getEntity('ScheduleRequest');
    scheduleRequestEntity.find({_id: {$in: srRecordIds}}, {path: 'Scheduler'}, function(err, records){
		if(err){
			var newErr = new Error();
            newErr.leval = 1;
            newErr.title = '【' + scheduleRequestEntity.Name + '】' + '查找错误';
            newErr.message = err.message;
            responseFun(newErr);
		}
		else{
			var recordIds = [];
			var recordsState = {};
			records.forEach(function(record){
				recordIds.push(record._id);
				recordsState[record._id] = record.Status;
			});
			entityCollection.getEntity('ScheduleRequest').updateByValue({_id: {$in: recordIds}}, {Status: CommonEnum.ScheduleStatus.Wait.Value}, function(){
				Promise.all(records.map((record) => executeRequest(srRecord))).then(function(data){
					responseFun(null, true);
				}).catch(function(err){
					responseFun(err);
				}).finally(function(){
					for(var p in recordsState){
						entityCollection.getEntity('ScheduleRequest').updateByValue({_id: p}, {Status: recordsState[p]});
					}
				});
			});	
		}
	});

	if(errs.length > 0){
		responseFun(errs);
	}
	else{
		responseFun(null, true);
	}
};
